﻿using System;
using System.Data;
using System.Configuration;

using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.ComponentModel;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using TA.JSON;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// A control event which can only be processed on the client.
	/// </summary>
	public class ClientEvent : SimpleClientEvent, IControlOwned
	{
		#region PUBLIC
		#region INIT
		/// <summary>
		/// Ctor.
		/// </summary>
		public ClientEvent()
		{
		}
		#endregion
		#region PROPS
		/// <summary>
		/// Gets the <see cref="TControl"/> which owns this event.
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public TControl Owner
		{
			get
			{
				return this._c;
			}
		}
		#endregion
		#region METHODS
		/// <summary>
		/// Returns client script which needs to be executed on the client to raise this event.
		/// </summary>
		/// <param name="argument">Used with server events only.</param>
		/// <returns></returns>
		public string GetEventScript(object argument)
		{
			string script = this.DoGetEventScript(argument);
			if (!string.IsNullOrEmpty(script))
				script = TPage.PrepareScript(script);
			return script;
		}
		/// <summary>
		/// Returns client script which needs to be executed on the client to raise this event on client only.
		/// </summary>
		/// <param name="argument"></param>
		/// <returns></returns>
		public virtual string GetEventClientScript(object argument)
		{
			StringBuilder sbScript = new StringBuilder();

			this.Client = (this.Client ?? "").Trim();
			if (!string.IsNullOrEmpty(this.Client))
			{
				if (rgxIsScript.IsMatch(this.Client))
					sbScript.AppendFormat("{0};", this.Client);
				else
					sbScript.AppendFormat("return {0}(event, {1});", this.Client, this.SerializeArgument(argument));
			}

			//_eventScript = true;
			return sbScript.ToString();
		}
		/// <summary>
		/// Outputs the event as HTML attributes in the standard format.
		/// </summary>
		/// <param name="writer"></param>
		public virtual void AddAttributes(HtmlTextWriter writer)
		{
			//if (_eventScript) return;
			this.Client = (this.Client ?? "").Trim();
			if (!string.IsNullOrEmpty(this.Client))
			{
				string name = this._name;
				//name = TPage.PrepareEventName(name);
				writer.AddAttribute(name + "-Client", this.PreparedClient);
			}
		}
		/// <summary>
		/// Not used.
		/// </summary>
		/// <param name="control"></param>
		public void SetOwner(TControl control)
		{
		}
		#endregion
		#endregion
		#region INTERNAL
		#region VARS
		static Regex rgxIsScript = new Regex(@"[^\w\._]");
		/// <summary>
		/// The control this event belongs to.
		/// </summary>
		protected TControl _c;
		/// <summary>
		/// The name of this event.
		/// </summary>
		protected string _name;
		//protected bool _eventScript = false;
		#endregion
		#region METHODS
		/// <summary>
		/// This method is called right after ctor from BaseControl.GetEvent() because generic parameters constraint don't support a ctor with parameters (like new(string a, ...))
		/// </summary>
		/// <param name="ctl"></param>
		/// <param name="name"></param>
		internal void Set(TControl ctl, string name)
		{
			this._c = ctl;
			this._name = name;
		}
		/// <summary>
		/// Serializes the event argument.
		/// </summary>
		/// <param name="argument"></param>
		/// <returns></returns>
		protected string SerializeArgument(object argument)
		{
			var sb = new StringBuilder();
			var jw = new JsonWriter(sb);
			jw.Value(argument);
			string res = sb.ToString();
			if (res.StartsWith("\"") && res.EndsWith("\""))
			{
				res = "'" + res.Substring(1, res.Length - 2) + "'";
			}
			return res;
		}
		/// <summary>
		/// Returns client script which needs to be executed on the client to raise this event.
		/// </summary>
		/// <param name="argument">Used with server events only.</param>
		/// <returns></returns>
		protected virtual string DoGetEventScript(object argument)
		{
			string script = this.GetEventClientScript(argument);

			if (!string.IsNullOrEmpty(script))
			{
				return string.Format("return $SimpleControl.RaiseClientEvent(event, function() {{ {0} }});", script);
			}
			return null;
		}
		#endregion
		#endregion
	}
}